package com.naiterui.ehp.bs.pharmacist.service.impl;

import java.util.HashMap;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.naiterui.common.redis.RedisUtil;
import com.naiterui.ehp.bp.constants.CommonConstant;
import com.naiterui.ehp.bp.support.exception.BusinessException;
import com.naiterui.ehp.bp.utils.date.DateUtil;
import com.naiterui.ehp.bp.utils.encypt.GengerCode;
import com.naiterui.ehp.bp.utils.lang.StringUtil;
import com.naiterui.ehp.bp.utils.sms.SMSUtil;
import com.naiterui.ehp.bs.pharmacist.controller.PharmacistSendSMSController;
import com.naiterui.ehp.bs.pharmacist.entity.Pharmacist;
import com.naiterui.ehp.bs.pharmacist.exception.ExceptionCodes;
import com.naiterui.ehp.bs.pharmacist.service.ILoginService;
import com.naiterui.ehp.bs.pharmacist.service.ISMSService;
import com.naiterui.ehp.bs.pharmacist.utils.Constants;
import com.naiterui.ehp.bs.pharmacist.utils.SignatureVerifyUtil;

/**
 * @Description TODO
 * @Author gongbaoqiang
 * @Date 2020/6/9 2:07 PM
 */
@Service
public class PharmacistSMSServiceImpl implements ISMSService {
    private static final Logger LOGGER = LoggerFactory.getLogger(PharmacistSendSMSController.class);

    @Autowired
    private ILoginService loginService;

    /**
     * @param phoneNum   输入手机号码
     * @param actionType 功能类型(1/注册；2/忘记密码；3/修改手机号；4/修改密码; 5/登录验证; 6/登录验证-2.5.0优化后)
     *
     * @return
     */
    @Override
    public void sendSMs(String phoneNum, Integer actionType, Long t, String sign) throws BusinessException {
        LOGGER.info("发送短信 请求参数：phoneNum = [{}], actionType = [{}], t = [{}], sign = [{}]", phoneNum, actionType, t, sign);

        // 1 手机号校验
        if (phoneNum == null || "".equals(phoneNum)) {
            LOGGER.info("{phoneNum} 手机号为空", phoneNum);
            throw new BusinessException(ExceptionCodes.SMS_PHONE_NULL);
        }
        if (!StringUtil.isMobileNum(phoneNum)) {
            LOGGER.error("{phoneNum} 不符合手机验证规则", phoneNum);
            throw new BusinessException(ExceptionCodes.SMS_PHONE_ERROR);
        }
        // 2 发送类型校验
        if (actionType == null) {
            throw new BusinessException(ExceptionCodes.SMS_PHONE_ACT_ERROR);
        }

        if (t == null || sign == null) {
            throw new BusinessException(ExceptionCodes.PARAM_ERROR);
        }

        // 签名校验
        Map<String, Object> signParams = new HashMap<>();
        signParams.put("phoneNum", phoneNum);
        signParams.put("actionType", actionType);
        signParams.put("t", t);
        boolean verify = SignatureVerifyUtil.verifySign(signParams, sign);
        if (!verify) {
            LOGGER.warn("签名校验失败signParams{}, sign:{}", signParams, sign);
            throw new BusinessException(ExceptionCodes.SIGN_ERR);
        }

        String cacheKey = "";
        // 1/注册；2/忘记密码；3/修改手机号;4/修改密码；5/登录验证；6/登录验证-2.5.0优化后; 7:修改签名密码
        switch (actionType) {
            case 1:
                Pharmacist pharmacist = loginService.findLoginByPhoneNum(phoneNum);
                if (pharmacist == null) {
                    throw new BusinessException(ExceptionCodes.PHARMACIST_ACCOUNT_NOT_EXISTS);
                }else if(Pharmacist.STATUS_ACTIVE.equals(pharmacist.getStatus())){
                    throw new BusinessException(ExceptionCodes.PHARMACIST_ALREADY_ACTIVE);
                }
                cacheKey = Constants.PHONE_REGIST_KEY + phoneNum;
                break;
            case 2:
                if (!existLogin(phoneNum)) {
                    throw new BusinessException(ExceptionCodes.PHARMACIST_ACCOUNT_NOT_EXISTS);
                }
                if (isForbidden(phoneNum)) {
                    throw new BusinessException(ExceptionCodes.PHARMACIST_ACCOUNT_NOT_NORMAL);
                }
                cacheKey = Constants.PHONE_FORGET_KEY + phoneNum;
                break;
            case 3:
                if (!existLogin(phoneNum)) {
                    throw new BusinessException(ExceptionCodes.REGIST_EXSIT);
                }
                cacheKey = Constants.PHONE_MODIFY_PHONE_KEY + phoneNum;
                break;
            case 4:
                if (!existLogin(phoneNum)) {
                    throw new BusinessException(ExceptionCodes.PHARMACIST_ACCOUNT_NOT_EXISTS);
                }
                if (isForbidden(phoneNum)) {
                    throw new BusinessException(ExceptionCodes.PHARMACIST_ACCOUNT_NOT_NORMAL);
                }
                cacheKey = Constants.PHONE_MODIFY_PWD_KEY + phoneNum;
                break;
            case 5:
                if (existLogin(phoneNum) && isForbidden(phoneNum)) {
                    throw new BusinessException(ExceptionCodes.PHARMACIST_ACCOUNT_NOT_NORMAL);
                }
                cacheKey = Constants.PHONE_LOGIN_PWD_KEY + phoneNum;
                break;
            case 6: // changed by chenlin 2.5.0 优化验证登录短信逻辑
                if (!existLogin(phoneNum)) {
                    throw new BusinessException(ExceptionCodes.PHARMACIST_ACCOUNT_NOT_EXISTS);
                }
                if (isForbidden(phoneNum)) {
                    throw new BusinessException(ExceptionCodes.PHARMACIST_ACCOUNT_NOT_NORMAL);
                }
                cacheKey = Constants.PHONE_LOGIN_PWD_KEY + phoneNum;
                break;
            case 7:
                if (!existLogin(phoneNum)) {
                    throw new BusinessException(ExceptionCodes.PHARMACIST_ACCOUNT_NOT_EXISTS);
                }
                if (isForbidden(phoneNum)) {
                    throw new BusinessException(ExceptionCodes.PHARMACIST_ACCOUNT_NOT_NORMAL);
                }
                cacheKey = Constants.PHONE_ESIGN_PWD_KEY + phoneNum;
                break;
            default:
                LOGGER.error(" {}发送短信验证码不正确", actionType);
                throw new BusinessException(ExceptionCodes.SMS_PHONE_ACT_ERROR);
        }
        String code = null;
        // V1.4 保存每次生成的验证码有效期为10分钟，如果用户10分钟内获取，则返回同一个验证码
        // String cacheCodeKey = cacheKey + "_code";
        // if (RedisUtil.keyOps().existsKey(cacheCodeKey)) {
        // code = RedisUtil.valueOps().getString(cacheCodeKey);
        // }
        // if (code == null) {
        // code = GengerCode.generateSmsCode();
        // RedisUtil.valueOps().set(cacheCodeKey, code, Constants.SAVE_VERIFY_CODE);
        // }

        // 每次生成的验证码有效期为10分钟，如果已使用则重新生成
        if (RedisUtil.keyOps().existsKey(cacheKey)) {
            code = RedisUtil.valueOps().getString(cacheKey);
        }
        if (code == null) {
            code = GengerCode.generateSmsCode();
        }
        try {
            if (RedisUtil.keyOps().existsKey(Constants.PHONE_SEND_TIME_KEY + cacheKey)) {
                LOGGER.info("发送验证码两次间隔小于1分钟,电话为phoneNum=" + phoneNum);
                throw new BusinessException(ExceptionCodes.SMS_PHONE_MAX_FREQUENCY);
            }
            // 验证用户错误输入次数是否达到上限
            if (SMSUtil.validUserOperatorFlag(cacheKey, CommonConstant.REDIS_PRE_PHARMACIST)) {
                LOGGER.info("发送验证码由于连续多次输入错误，账号暂时被锁定,电话为phoneNum=" + phoneNum);
                throw new BusinessException(ExceptionCodes.SMS_PHONE_VALID_MAX_COUNT);
            }
            // 验证码存放10分钟
            RedisUtil.valueOps().set(cacheKey, code, Constants.SAVE_VERIFY_CODE);
            // 验证码发送时间间隔
            // RedisUtil.valueOps().set(Constants.PHONE_SEND_TIME_KEY + phoneNum, "", Constants.SEND_SPACE);
            RedisUtil.valueOps().set(Constants.PHONE_SEND_TIME_KEY + cacheKey, "", Constants.SEND_SPACE);
            // 统计当天发送量,如果发送key不存在，则删除以前统计量，否则在原统计量上激增
            if (!RedisUtil.keyOps().existsKey(Constants.PHONE_DAY_SEND_COUNT_KEY + phoneNum)) {
                RedisUtil.keyOps().delete(Constants.PHONE_SEND_COUNT_KEY + phoneNum);
                RedisUtil.valueOps().set(Constants.PHONE_DAY_SEND_COUNT_KEY + phoneNum, "", DateUtil.getDayOfSecond());
            }
            // 验证码发送总次数统计
            long count = RedisUtil.keyOps().incr(Constants.PHONE_SEND_COUNT_KEY + phoneNum);
            if (count > Constants.SEND_MAX_COUNT) {
                LOGGER.info("当天发送验证码次数已经超过10次，电话为phoneNum=" + phoneNum);
                throw new BusinessException(ExceptionCodes.SMS_PHONE_MAX_COUNT);
            }
        } catch (BusinessException e) {
            throw e;
        } catch (Exception e) {
            e.printStackTrace();
            LOGGER.error("向redis存放医生验证码失败,phoneNum=" + phoneNum);
            throw new BusinessException(ExceptionCodes.FAILED);
        }

        // 调用远程接口，发送验证码
        SMSUtil.Template tmpl = SMSUtil.Template.PWD;
        LOGGER.info(code);
        try {
            SMSUtil.sendSMS(phoneNum, tmpl, code);
        } catch (Exception e) {
            e.printStackTrace();
            LOGGER.error("获取验证码失败，电话为phoneNum=" + phoneNum);
            throw new BusinessException(ExceptionCodes.FAILED);
        }
    }


    private boolean isForbidden(String phoneNum) {
        // 药师是否已激活
        Pharmacist pharmacist = loginService.findLoginByPhoneNum(phoneNum);
        return pharmacist != null && pharmacist.getStatus() != null && pharmacist.getStatus() != Pharmacist.STATUS_ACTIVE;
    }

    private boolean existLogin(String phoneNum) {
        // 读库获取
        return loginService.findLoginByPhoneNum(phoneNum) != null;
    }

}
